// 引入配置文件（系统基础配置）
const config = require('../config/app.config')
const webpack = require('webpack')
const path = require('path')
// 查看打包情况
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
  .BundleAnalyzerPlugin
const ReactLoadablePlugin = require('@loadable/webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const nodeExternals = require('webpack-node-externals')
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

const getEntry = (target, is_dev, is_ssr) => {
  let entry

  if (target === 'web') {
    entry = {
      app: [path.join(config.CLIENT_ROOT, 'client_index.jsx')]
    }

    if (is_dev) {
      entry.app.push('webpack-hot-middleware/client?noInfo=true&reload=true')
    }
  } else {
    entry = {
      server: path.join(config.MIDDLEWARE_ROOT, 'AppSSR.js'),
      app: path.join(config.CLIENT_ROOT, 'client_index.jsx')
    }
  }

  return entry
}

const getOutput = (target, is_dev, is_ssr) => {
  let output
  if (target === 'web') {
    if (is_dev) {
      output = {
        path: config.WEBPACK_CLIENT_ROOT,
        pathinfo: true,
        filename: '[name].js',
        chunkFilename: 'chunk.[name].js',
        assetModuleFilename: 'images/[hash:8].[name].[ext]',
        publicPath: '/',
        environment: {
          // 是否使用箭头函数
          arrowFunction: false,
          destructuring: false
        },
      }
    } else {
      output = {
        path: config.WEBPACK_CLIENT_ROOT,
        filename: '[name].[chunkhash:8].js',
        chunkFilename: 'chunk.[name].[chunkhash:8].js',
        assetModuleFilename: 'images/[hash:8].[name].[ext]',
        publicPath: '/',
        environment: {
          // 是否使用箭头函数
          arrowFunction: false,
          destructuring: false
        },
      }
    }
  } else {
    output = {
      path: config.WEBPACK_SERVER_ROOT,
      filename: '[name].js',
      libraryExport: 'default',
      libraryTarget: 'commonjs2'
    }
  }

  return output
}

const getPlugins = (target, is_dev, is_ssr) => {
  const plugins = [
    new webpack.NoEmitOnErrorsPlugin(),
    // SSR按需加载
    new ReactLoadablePlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        IS_DEV: is_dev,
        IS_SSR: is_ssr
      }
    }),
    // 打包时显示进度
    new webpack.ProgressPlugin(function (percentage, msg) {
      let str = `${Math.floor(percentage * 100)}% ${msg}`
      process.stderr.write(`${str}\r`)
    }),
    new BundleAnalyzerPlugin({ analyzerMode: 'static' }),
    // 每次打包清理掉之前的内容
    new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: ['!.gitignore'] })
  ]

  if (is_dev) {
    // 打包情况
    // plugins.push(new BundleAnalyzerPlugin())
  }

  if (is_dev) {
    // 为 react-refresh 添加
    plugins.push(new ReactRefreshPlugin())
    // 热更新
    plugins.push(new webpack.HotModuleReplacementPlugin())
  } else {
    // 打包样式文件
    plugins.push(new MiniCssExtractPlugin({
      filename: is_dev ? '[name].css' : '[name].[contenthash].css',
      chunkFilename: is_dev ? '[id].css' : '[id].[contenthash].css'
    }))
  }

  return plugins
}

const getModule = (target, is_dev, is_ssr) => ({
  rules: [
    {
      test: /(\.jsx|\.js)$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        presets: ['@babel/env', '@babel/preset-react'],
        // 为 react-refresh 添加
        plugins: is_dev ? ['react-refresh/babel'] : [],
      },
    },
    {
      test: /\.(sa|sc)ss$/i,
      use: [
        is_dev ? "style-loader" : MiniCssExtractPlugin.loader,
        {
          loader: "css-loader",
          options: {
            modules: {
              localIdentName: is_dev
                ? '[path][name]__[local]--[hash:base64:5]'
                : '[hash:base64]'
            }
          }
        },
        // "postcss-loader",
        "sass-loader",
      ],
    },
    {
      test: /\.css$/i,
      use: [
        is_dev ? "style-loader" : MiniCssExtractPlugin.loader,
        {
          loader: "css-loader"
        }
      ],
    },
    {
      test: /\.(png|jpe?g|gif|svg)$/i,
      type: 'asset'
    }
  ]
})

const getOptimization = (target, is_dev, is_ssr) => {
  if (target === 'node') return {}
  let optimization = {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /node_modules/, // 指定是node_modules下的第三方包
          chunks: 'initial',
          name: 'vendor', // 打包后的文件名，任意命名
          // 设置优先级，防止和自定义的公共代码提取时被覆盖，不进行打包
          priority: 10
        }
      }
    }
  }

  // if (!is_dev) {
  //   optimization.splitChunks.maxSize = 2048000
  // }

  return optimization
}

const getConfig = (target, is_dev, is_ssr) => {
  const externals = []
  if (target === 'node') {
    // 在打包node的时候 不把依赖包打包进去
    externals.push(nodeExternals())
  }

  return {
    // webpack 打包的模式
    mode: is_dev ? 'development' : 'production',
    devServer: {
      hot: true
    },
    target,
    entry: getEntry(target, is_dev, is_ssr),
    output: getOutput(target, is_dev, is_ssr),
    module: getModule(target, is_dev, is_ssr),
    plugins: getPlugins(target, is_dev, is_ssr),
    externals,
    optimization: getOptimization(target, is_dev, is_ssr),
    resolve: {
      extensions: ['.jsx', '.js'],
      alias: {
        '@': path.resolve('client/')
      }
    },
    devtool: is_dev ? 'eval-source-map' : 'source-map'
  }
}

module.exports = [
  getConfig('node', config.DEBUG, config.SSR),
  getConfig('web', config.DEBUG, config.SSR)
]
